﻿using System.Collections.Concurrent;
using Microsoft.Extensions.Caching.Memory;

namespace Foundation.Core
{
    public class SelectCollectionStore
    {
        public static readonly SelectCollectionStore Default = new SelectCollectionStore();

        public readonly MemoryCache MemoryCache = new MemoryCache(Microsoft.Extensions.Options.Options.Create(new MemoryCacheOptions()));

        private ConcurrentDictionary<string, Dictionary<SelectCategory, SelectCollectionStoreItem>> _collectionItems = new ConcurrentDictionary<string, Dictionary<SelectCategory, SelectCollectionStoreItem>>();

        public bool TryGetCollection(string key, SelectCategory category, out SelectCollection collection)
        {
            collection = default;
            if (_collectionItems.TryGetValue(key, out var dict)
                && dict.TryGetValue(category, out var item)
                && item.Collection != null
                && (!item.ExpirationTime.HasValue || item.ExpirationTime > DateTime.Now))
            {
                collection = item.Collection;

                return true;
            }

            return false;
        }

        internal void SetCollection(string key, SelectCategory category, SelectCollection collection)
        {
            var item = GetOrAdd(key, category);

            if (item.Options == null)
            {
                throw new AppException($"key:{key},category:{category} 未找到");
            }

            item.Collection = collection;
            item.ExpirationTime = item.Options.CacheTime.HasValue ? DateTime.Now.Add(item.Options.CacheTime.Value) : DateTime.MaxValue;
        }

        internal void RemoveCollection(string key, SelectCategory category)
        {
            if (_collectionItems.TryGetValue(key, out var dict) && dict.TryGetValue(category, out var item))
            {
                item.Collection = null;
            }
        }

        public void AddOptions(SelectItemOptions options)
        {
            var item = GetOrAdd(options.Key, options.Category);

            if (item.Options != null)
            {
                throw new AppException($"key:{options.Key},category:{options.Category} 配置已存在！");
            }

            item.Options = options;

            if (!options.Items.IsNullOrEmpty())
            {
                item.Collection = new SelectCollection(options.Category, options.Items);
            }
        }

        public bool IsExists(string key, SelectCategory category)
        {
            return TryGetOptions(key, category, out var _);
        }

        public bool IsExists(string key, Type type)
        {
            var exist = TryGetOptions(key, SelectCategory.Constant, out var options);

            if (exist && options != null)
            {
                return options.ItemDeclaringType == type;
            }

            return exist;
        }

        public SelectItemOptions GetOptions(string key, SelectCategory category)
        {
            TryGetOptions(key, category, out var item);

            return item;
        }

        public bool TryGetOptions(string key, SelectCategory category, out SelectItemOptions options)
        {
            options = default;
            if (TryGetItem(key, category, out var item) && item.Options != null)
            {
                options = item.Options;

                return true;
            }

            return false;
        }

        protected bool TryGetItem(string key, SelectCategory category, out SelectCollectionStoreItem item)
        {
            item = default;

            return _collectionItems.TryGetValue(key, out var dict) && dict.TryGetValue(category, out item);
        }

        protected SelectCollectionStoreItem GetOrAdd(string key, SelectCategory category)
        {
            var dict = _collectionItems.GetOrAdd(key, (k) => new Dictionary<SelectCategory, SelectCollectionStoreItem>());

            if (!dict.TryGetValue(category, out var item))
            {
                item = new SelectCollectionStoreItem
                {
                    Key = key,
                    Category = category,
                };

                dict.Add(category, item);
            }

            return item;
        }
    }

    public class SelectCollectionStoreItem
    {
        public string Key { get; set; }

        public SelectCategory Category { get; set; }

        public SelectItemOptions Options { get; set; }

        public SelectCollection Collection { get; set; }

        public DateTime? ExpirationTime { get; set; }
    }
}
